home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-09-16 | 29.1 KB | 694 lines | [TEXT/CCL2] |
- ;-*- Mode: Lisp; Package: CCL -*-
- ; help-manager.lisp
-
- (in-package :ccl)
-
- ;; 04/28/93 mwp Release
- ;; 01/07/93 bill Fix missing descenders bug by setting fontascent & lineheight in help-tehandle
- ;; 11/09/92 bill checked-help-string
- ;; 11/02/92 bill menu-hmnu-id is no more.
- ;;-------------- 2.0
- ;; 11/12/91 bill Changed WINDOW... to WindowRecord... Put $menuList at :compile-toplevel. (from dds)
- ;; 10/29/91 bill a help-spec can be an integer, denoting the 'STR ' resource of that number
- ;; functional help-specs for menu items
- ;; 07/05/91 bill With Randy Carr's help, fix missing descenders on bottom line of
- ;; menu-item help.
- ;; Add MBAR defproc handling to get menubar help.
- ;; 06/18/91 bill Works for menu items now.
- ;; deepest-view-contained-by-me-below-mouse -> find-clicked-subview
- ;; speed window-null-event-handler up a little bit, though
- ;; system 7 seems to steal most of the machine when help is on.
- ;; 4/29/91 bill *help-manager-present*, view-help-string -> help-string
- ;; Friday September 28,1990 0:25am - moved to #_ interface
- ;; Friday April 5,1991 2:25pm made it run again in 7.0b6
- ;; Friday April 5,1991 3:40pm make the check be on window-null-event-handler, instead of enter and leave.
-
- ;;;****************************************************************
- ;; support for some of the help manager. The idea is that you define
- ;; a method for help-string for your view. Then, if help is enabled
- ;; a balloon will pop up with that string (computed at pop time).
- ;; the default method says something about views and their containers.
-
- ;; Interface:
-
- ;; (help-string view) -> the string for the view that should appear in the help balloon
- ;; (help-tip-point view) -> The point where the tip of the balloons should be. Defaults to where the mouse is
- ;; (set-help state) -> Turn balloon help on or off (t or nil)
- ;; (help-on?) -> returns t or nil
- ;; help-always-on-mixin -> Mix into a view to make help always be on in that view
- ;; *view-nesting-help* -> If t then when help is on, default method for view help string tells something
- ;; about the view container hierarchy of the view. Initially t
-
- (eval-when (:compile-toplevel :load-toplevel :execute)
- (require "RESOURCES")
-
- (export '(view-help-event-handler help-string help-on? set-help
- help-tip-point help-always-on-mixin
- help-spec)))
-
- ;; Here is an example of an extension for fred windows
- (defmethod help-string ((f fred-window))
- (or (help-resource-string f)
- "This is a Fred window. Fred deliberately resembles Emacs. Fred is your friend."))
-
- (defmethod help-string ((l listener))
- (or (help-resource-string l)
- "This is a Lisp listener. Enter a Lisp expression and it will be evaluated."))
-
- ;;;****************************************************************
- ;; globals
-
- (defvar *view-with-balloon* nil "The view that has a help balloon on top of it now")
- (defvar *view-nesting-help* t "Set to have descriptions of views when help is on")
-
- ;;;****************************************************************
- ;; view info help strings
-
- ; The help-string method always returns a string.
- ; The default method looks for a help-spec and returns its string.
- (defmethod help-string (thing)
- (help-resource-string thing))
-
- (defvar *help-resource-file-refnum* nil)
-
- ; Specialize this if you store your help resources in a different file
- (defmethod help-resource-file ((a application))
- (get-doc-string-file t))
-
- ; Specialize this if you store your help resources in your application's resource fork
- (defmethod help-resource-file-refnum ((a application))
- (or *help-resource-file-refnum*
- (let ((file (help-resource-file a)))
- (and file
- (setq *help-resource-file-refnum*
- (using-resource-file (current-resource-file)
- (open-resource-file file :errorp nil)))))))
-
- (defun close-help-resource-file ()
- (let ((refnum *help-resource-file-refnum*))
- (when refnum
- (setq *help-resource-file-refnum* nil)
- (close-resource-file refnum))))
-
- (pushnew 'close-help-resource-file *lisp-cleanup-functions*)
-
- ; This is where the parsing of the help-spec happens
- (defun help-resource-string (thing &aux refnum)
- (labels ((resolve-restype (restype thing)
- (cond ((null restype) nil)
- ((stringp restype) restype)
- ((or (functionp restype) (symbolp restype))
- (resolve-restype (funcall restype thing) thing))
- ((and (or (integerp restype) (listp restype))
- (setq refnum (help-resource-file-refnum *application*))
- (using-resource-file refnum
- (block foo
- (return-from resolve-restype
- (cond ((integerp restype)
- (get-string restype))
- ((null (cdr restype))
- (get-string (car restype)))
- ((and (listp (cdr restype)) (null (cddr restype)))
- (get-ind-string (car restype) (cadr restype)))
- (t (return-from foo nil))))))))
- (t (error "Malformed help-spec: ~s" restype)))))
- (resolve-restype (help-spec thing) thing)))
-
- ; help-spec can return the following types of values:
- ;
- ; NIL
- ; this thing has no help resource.
- ; a string
- ; The string is the help string.
- ; A function or symbol
- ; The help-spec is the result of funcalling the function or symbol
- ; with the object as the single argument.
- ; A list of the form (name-or-number) or a number
- ; There is a 'STR ' resource whose name or number is the car of the list
- ; a list of the form (name-or-number index)
- ; There is a 'STR#' resource with the given name or number.
- ; The help string is the INDEX'th string in that resource.
-
- (defmethod help-spec (thing)
- (declare (ignore thing))
- nil)
-
- (defmethod help-spec ((view simple-view))
- (view-get view :help-spec))
-
- (defmethod (setf help-spec) (spec (view simple-view))
- (setf (view-get view :help-spec) spec))
-
- ; Menus and menu-items have a HELP-SPEC slot
-
- ; Unless the user provides a help-spec method, the default
- ; help-string for a simple-view is the view nesting help.
- (defmethod help-string ((v simple-view))
- (or (help-resource-string v)
- (and *view-nesting-help*
- (let ((help-string (make-string-output-stream)))
- (view-container-info v help-string "This is ")
- (format help-string ".")
- (coerce (string-output-stream-string help-string)
- 'simple-string)))))
-
- (defmethod view-container-info ((v simple-view) stream &optional (intro " inside "))
- (format stream intro)
- (typecase v
- (dialog (if (window-title v)
- (format stream "the dialog ~s (type ~A)"
- (window-title v)
- (string-capitalize (type-of v)))
- (format stream "a dialog of type ~A"
- (string-capitalize (type-of v)))))
- (window (if (window-title v)
- (format stream "the window ~s (type ~A)"
- (window-title v)
- (string-capitalize (type-of v)))
- (format stream "a window of type ~A"
- (string-capitalize (type-of v)))))
- (t (format stream "a view of type ~A" (string-capitalize (type-of v)))))
- (when (view-container v)
- (view-container-info (view-container v) stream)))
-
- ;;;****************************************************************
- ;; we use a textedit record here, since we need strings of arbitrary size.
-
- (defparameter *help-tehandle* nil)
- (defparameter *help-message-record* nil)
- ;; needs to be allocated and held, since the help manager can hold onto this for longer
- ;; than the body of an rlet
-
- (def-ccl-pointers help-manager ()
- (setq *help-tehandle* nil)
- (setq *help-message-record* nil))
-
- (defun help-tehandle (string &aux (length (length string)))
- "returns a texthandle with string as it's string contents. There is one terec *help-tehandle*"
- (let ((terec *help-tehandle*)
- font size)
- (if terec
- ; Necessary because bug in system neglects to initialize these.
- (setf (href terec :terec.destrect.topleft) #@(5 5)
- (href terec :terec.destrect.botRight) #@(100 100)
- (href terec :terec.viewrect.topleft) #@(5 5)
- (href terec :terec.viewrect.botRight) #@(100 100))
- (rlet ((r :rect
- :topleft #@(5 5)
- :bottomright #@(100 100)))
- (setq *help-tehandle* (setq terec (#_tenew r r)))))
- (rlet ((font-info :integer))
- (#_HMGetFont font-info)
- (setf (href terec :terec.txfont)
- (setq font (%get-word font-info)))
- (#_HMGetFontSize font-info)
- (setf (href terec :terec.txsize)
- (setq size (%get-word font-info)))
- (setf (href terec :terec.txmode) 0)
- (setf (href terec :terec.txface) 0))
- (multiple-value-bind (ascent descent maxwid leading)
- (font-codes-info (make-point 0 font) (make-point size 0))
- (declare (ignore maxwid))
- (setf (href terec :terec.fontascent) ascent
- ; maybe this should be just (+ ascent descent)
- (href terec :terec.lineheight) (+ ascent descent leading)))
- (with-cstr (cs string 0 length)
- (#_tesettext cs length terec))
- terec))
-
- ; debugging
- (defun help-tehandle-string ()
- (and *help-tehandle*
- (let ((str (#_tegettext :ptr *help-tehandle* :ptr)))
- (%str-from-ptr (%get-ptr str) (href *help-tehandle* terec.telength)))))
-
- (defmethod setup-help-message (string)
- (unless *help-message-record*
- (setq *help-message-record* (make-record :hmmessagerecord :hmmHelpType #$khmmtehandle)))
- (rset *help-message-record* :hmmessagerecord.hmmTEHandle (help-tehandle string)))
-
- ;;;****************************************************************
- ;; Information about placement of balloon
-
- (defmethod help-tip-point ((v simple-view))
- (view-mouse-position v))
-
- ;; save bits if the help window would be completely enclosed in the window. Customize this if you want.
- (defmethod help-save-bits? ((v simple-view))
- (rlet ((balloonrect :rect))
- (#_hmballoonrect :ptr *help-message-record* :ptr balloonrect :word)
- (let ((wptr (wptr v)))
- (rlet ((intersect :rect)
- (window-rect :rect
- :topleft (pref wptr windowRecord.portrect.topleft)
- :bottomright (pref wptr windowRecord.portrect.bottomright)
- ))
- (#_offsetrect :ptr balloonrect :long (view-mouse-position (view-window v)))
- (#_sectrect window-rect balloonrect intersect)
- (and
- (= (pref intersect rect.topleft) (pref balloonrect rect.topleft))
- (= (pref intersect rect.bottomright) (pref balloonrect rect.bottomright)))
- ))))
-
- ;;;****************************************************************
-
- (defmethod remove-balloon ((v simple-view))
- (when *view-with-balloon*
- (let ((w (view-window v)))
- (when (and (#_hmisballoon)
- (point<= #@(0 0) (view-mouse-position w) (view-size w)))
- (#_hmremoveballoon))
- (setq *view-with-balloon* nil))
- (let ((w (view-window v)))
- (and w (window-update-event-handler w)))))
-
- (defmethod view-click-event-handler :before ((v simple-view) where)
- (declare (ignore where))
- (when *help-manager-present*
- (#_hmremoveballoon)))
-
- ; Used to prevent menubar help from thrashing
- (defvar *last-help-item* nil)
-
- ;; we pass no hot rect here, since leave event handler takes care of removing the balloon
- (defmethod show-balloon (thing tip save-bits)
- (setq *last-help-item* thing)
- (#_hmshowballoon *help-message-record*
- tip (%null-ptr) (%null-ptr) 0 0
- (if save-bits
- (if (fixnump save-bits) save-bits #$khmsavebitsnowindow)
- #$khmregularwindow)
- ))
-
- (defun checked-help-string (view)
- (let ((string (help-string view)))
- (when string
- (setq string (string string))
- (unless (eql 0 (length string))
- string))))
-
- (defmethod view-put-up-balloon ((v simple-view) &optional string)
- (when (not (#_hmgetballoons :boolean)) (return-from view-put-up-balloon nil))
- (multiple-value-bind (string save-bits)
- (or string (checked-help-string v))
- (when string ;; null means that we don't want help
- (setup-help-message string)
- (let* ((tip (with-focused-view v
- (%local-to-global (wptr v) (help-tip-point v)))))
- ;; make sure we are still in window
- (let ((w (view-window v)))
- (when (not (point<= #@(0 0) (view-mouse-position w) (view-size w)))
- (return-from view-put-up-balloon)))
- ;; check if we are still in the view
- (when (eq v (find-clicked-subview v (view-mouse-position v)))
- ;; doobeedoo
- (let ((res (show-balloon
- v tip
- (and save-bits (help-save-bits? v)))))
- (cond ((and (= res -852) save-bits)
- ; out of memory, there isn't enough room on the heap. Try to show it without saving bits.
- (show-balloon v tip nil))
- ;; mouse moving too quickly just pass
- ((= res -853))
- ((minusp res)
- (rset *help-message-record*
- :hmmessagerecord.hmmTehandle
- (help-tehandle
- (format nil "Help Manager Error: ~A" res)))
- (show-balloon v tip nil))
- ((zerop res) (setq *view-with-balloon* v)))))))))
-
-
- ;;****************************************************************
- ;; do the check in window-null-event-handler. Originally I had it in on the enter and leave handlers,
- ;; but that was too flakey. For one thing, the enter handler gets called and the mouse may still be moving,
- ;; in which case the balloon manager punts. You want to check again in a little while to see if
- ;; the mouse has settled down. Also, the leave handler is called way after the mouse leaves, sometimes,
- ;; and you have to check if you are still in the content area of the window so as not to remove someone
- ;; else's balloons.
-
- #|
- (defmethod window-null-event-handler :after ((w window))
- (if (help-on?)
- (show-mouse-view-balloon)
- (setq *view-with-balloon* nil)))
- |#
-
- ; This does the actual showing of the balloon
- ; Called by the window-null-event-handler method below
- (defun show-mouse-view-balloon ()
- (let ((mouse-view *mouse-view*))
- ;; if we go outside the content region, then another balloon has taken over, and we just return
- (unless mouse-view
- (setq *view-with-balloon* nil)
- (return-from show-mouse-view-balloon))
- ;; no balloon means someone else has put up a balloon or gotton rid of ours
- (when (not (#_hmisballoon)) (setq *view-with-balloon* nil))
- ;;if we are not in the same view as before, get rid of old, and put up new
- (when (neq *view-with-balloon* mouse-view)
- (#_hmremoveballoon)
- (view-put-up-balloon mouse-view))))
-
- ;;;****************************************************************
- ;; help state
-
- ;; help-on? is defined by the resident part of MCL
-
- (defun set-help (boolean)
- (when *help-manager-present*
- (without-interrupts
- (when (null boolean)
- (#_hmremoveballoon)
- (setq *view-with-balloon* nil))
- (#_hmsetballoons boolean))))
-
- ;;;****************************************************************
- ;; a mixin for views which always want to have help active.
-
- (defclass help-always-on-mixin () ((help-state)))
-
- (defmethod set-view-container :after ((v help-always-on-mixin) ignore)
- (declare (ignore ignore))
- (setf (slot-value v 'help-state) (help-on?)))
-
- (defmethod view-mouse-enter-event-handler :before ((v help-always-on-mixin))
- (unless (slot-boundp v 'help-state)
- (setf (slot-value v 'help-state) (help-on?)))
- (set-help t)
- )
-
- (defmethod view-mouse-leave-event-handler :before ((v help-always-on-mixin))
- (set-help (slot-value v 'help-state))
- )
-
- (defmethod view-deactive-event-handler :before ((v help-always-on-mixin))
- (set-help (slot-value v 'help-state)))
-
- (defmethod (setf wptr) :before (new-value (v help-always-on-mixin))
- (when (and (null new-value) (slot-boundp v 'help-state))
- (set-help (slot-value v 'help-state))
- ))
-
- ;;;****************************************************************
- ;; Help for menu-items
- ;;
-
- ; HELP-SPEC's for menus & menu-items are a little more general than those
- ; for views. In addition to strings, 'STR ' & 'STR#' resource specs, the
- ; help-spec for a menu-item can be of the form:
- ;
- ; (<type> enabled-spec disabled-spec &optional checked-spec other-spec)
- ;
- ; <type> can be:
- ; :string - each of the xxx-spec's is a string
- ; :|STR | - each of the xxx-spec's is the name or number of a 'STR ' resource
- ; (:|STR#| name-or-number) or just a fixnum or string denoting the name-or-number
- ; each of the xxx-spec's is the index of a string in
- ; the 'STR#' resource with the given name-or-number
- ;
- ; In this case the enabled-spec is the help string for the menu-item when
- ; it is enabled, the disabled-spec when it is disabled, the checked-spec
- ; when it is enabled and checked, and the other-spec when it is enabled
- ; and has a marker that is not the check-mark.
- ;
- ; HELP-SPEC for a menu may return a specification for the menu's help
- ; string and the default help-string for all the menu-items.
- ; This is of the form (VALUES menu-spec default-spec).
- ; If the help-spec for a menu is not a list whose car is the symbol VALUES,
- ; then there is no default-spec, and the returned value is the menu-spec.
- ;
- ; Any menu-item that has no HELP-SPEC (for which HELP-SPEC returns the
- ; default of NIL) will use the default-spec. If there is a default-spec
- ; and you want no help for a menu-item, return :SKIP as its HELP-SPEC.
-
- (defmethod help-string ((item menu-item))
- (let ((spec (help-spec item))
- (state (if (menu-item-enabled-p item)
- (let ((check (menu-item-check-mark item)))
- (if check
- (if (eql #\CheckMark check) 2 3)
- 0))
- 1)))
- (cond ((null spec)
- (setq spec (help-spec (menu-item-owner item)))
- (if (and (listp spec) (eq (car spec) 'values))
- (%menu-help-string item (caddr spec) state)
- nil))
- ((eq spec :skip) nil)
- (t (%menu-help-string item spec state)))))
-
- (defmethod help-string ((menu menu))
- (let ((spec (help-spec menu)))
- (if (and (listp spec) (eq (car spec) 'values))
- (setq spec (cadr spec)))
- (when spec
- (%menu-help-string menu spec (if (menu-enabled-p menu) 0 1)))))
-
- (defun %menu-help-string (item spec &optional (state 0))
- (labels ((refnum ()
- (or (help-resource-file-refnum *application*) (current-resource-file)))
- (str-item (&rest rest)
- (using-resource-file (refnum)
- (get-string (or (nth state rest) (car rest)) t)))
- (str#-item (n &rest rest)
- (using-resource-file (refnum)
- (get-ind-string n (or (nth state rest) (car rest)) t)))
- (string-item (&rest rest)
- (or (nth state rest) (car rest)))
- (malformed (spec)
- (error "Malformed help-spec: ~s" spec)))
- (declare (dynamic-extent #'str-item #'str-#item #'string-item))
- (cond ((functionp spec) (%menu-help-string item (funcall spec item) state))
- ((stringp spec) spec)
- ((fixnump spec) (str-item spec))
- ((and (listp spec) (null (cdr spec)))
- (str-item (car spec)))
- ((and (listp spec) (listp (cdr spec))
- (null (cddr spec)))
- (str#-item (car spec) (cadr spec)))
- ((and (listp spec) (<= 3 (length spec) 5))
- (let ((car (car spec))
- (cdr (cdr spec))
- id)
- (cond ((eq car :string)
- (apply #'string-item cdr))
- ((eq car :|STR |)
- (apply #'str-item cdr))
- ((or (and (listp car)
- (eq (car car) :|STR#|)
- (listp (cdr car))
- (null (cddr car))
- (setq id (cadr car)))
- (or (fixnump (setq id car)) (stringp car)))
- (apply #'str#-item id cdr))
- (t (malformed spec)))))
- (t (malformed spec)))))
-
- (defun show-balloon-string (thing string tip &optional (save-bits? t))
- (setup-help-message string)
- (show-balloon thing tip save-bits?))
-
- (defvar *mbar-proc* nil)
-
- (eval-when (:compile-toplevel :execute)
- (let ((*warn-if-redefine* nil))
- (defconstant $menuList #xa1c))
- )
-
- (defun menu-edges (menu &optional (menu-handle (menu-handle menu)))
- (with-macptrs ((menu-list (%get-ptr (%get-ptr (%int-to-ptr $menuList))))
- temp)
- (let ((count (floor (%get-word menu-list) 6)))
- (dotimes (i count)
- (declare (fixnum i))
- (%incf-ptr menu-list 6)
- (%setf-macptr temp (%get-ptr menu-list))
- (when (eql menu-handle temp)
- (let ((left (%get-word menu-list 4))
- (width (with-font-codes 0 0
- (string-width (menu-title menu)))))
- ; The six pixel spacing was determined by experiment
- (return (values left (+ left 6 width 6)))))))))
-
- ; MCL shows help strings for pointing at the menubar the same way the System
- ; help manager does: ask the Menu Bar Defproc which menu we're pointing at.
- ; See IM V-251 for documentation of the menubar defproc.
- ; This is called whether or not there is a window showing.
- (defmethod window-null-event-handler :after (w)
- (declare (ignore w))
- (when (and *foreground* (help-on?))
- (let ((mbar-proc *mbar-proc*))
- (unless (typep mbar-proc 'macptr)
- (setq mbar-proc (setq *mbar-proc* (get-resource :MBDF 0))))
- (when (typep mbar-proc 'macptr)
- (without-interrupts
- (let* ((mouse (view-mouse-position nil))
- (menu-index (ff-call (%get-ptr mbar-proc)
- :word 0 ; mbVariant
- :word 1 ; message #1: Hit
- :word 0 ; parameter 1: ignored
- :long mouse ; parameter 2: mouse
- :long
- ))
- (last-help-item *last-help-item*))
- (if (>= menu-index 6) ; mouse in menubar
- (let ((menu (nth (1- (floor menu-index 6)) %menubar)))
- (when menu
- (unless (and (eq menu last-help-item) (#_hmIsBalloon))
- (setq *last-help-item* nil)
- (let ((string (checked-help-string menu)))
- (setq *view-with-balloon* nil)
- (if string
- (multiple-value-bind (left right) (menu-edges menu)
- (setq mouse (make-point (if left (ash (+ left right) -1)
- (point-h mouse))
- (%get-word (%int-to-ptr #$mbarHeight))))
- (show-balloon-string menu string mouse nil))
- (unless (eq menu *apple-menu*)
- (#_HmRemoveBalloon)))))))
- (progn
- (setq *last-help-item* nil)
- (show-mouse-view-balloon)))))))))
-
- ; MCL shows help strings for menu-items by patching the trap _hmShowMenuHelp
- ; which is called by the standard menu definition procedure.
-
- #|
- ; This is the source code for the *hmShowMenuBalloon-patch* parameter below
-
- (require "LAPMACROS")
-
- (defun hmShowMenuBalloon-patch (&lap 0)
- (lap
- @lisp-entry
- (dc.w 0 0)
- @old-trap-address
- (dc.w 0 0)
- (if# (eq (cmp.w ($ 3589) d0)) ; selector for _hmShowMenuBalloon
- ; (dc.w _debugger)
- (movem.l #(d0 a0 a1) -@sp)
- (sub.l ($ 30) sp) ; another stack frame
- (lea @sp a1)
- (lea (sp (+ 30 12 4)) a0)
- (move.w ($ 15) d0)
- (dbfloop d0 (move.w a0@+ a1@+))
- (move.l (^ @lisp-entry) a0)
- (jsr @a0)
- (move.w sp@+ d0)
- (if# (eq (add.w ($ 1) d0)) ; Returned #xffff: call the usual version
- (movem.l sp@+ #(d0 a0 a1))
- (bra @nopatch)
- else#
- (sub.w ($ 1) d0)
- (move.l (sp 12) (sp (+ 12 4 24))) ; return address
- (move.w d0 (sp (+ 12 4 28))) ; return value
- (movem.l sp@+ #(d0 a0 a1))
- (add.l ($ (+ 4 24)) sp)
- (rts)))
- @nopatch
- (spush (^ @old-trap-address))
- (rts)))
-
- (defun *hmShowMenuBalloon-patch* ()
- (let* ((vector (%lfun-vector #'hmShowMenuBalloon-patch))
- (patch-address (%address-of #'hmShowMenuBalloon-patch))
- (offset (ash (- patch-address (+ (%address-of vector) 7)) -1))
- (size (- (uvsize vector) offset))
- (res (make-array size)))
- (dotimes (i size)
- (setf (aref res i) (uvref vector (+ offset i))))
- res))
-
- |#
-
- (defparameter *hmShowMenuBalloon-patch*
- (if (fboundp '*hmShowMenuBalloon-patch*)
- (funcall '*hmShowMenuBalloon-patch*)
- ; This is the vector returned by the *hmShowMenuBalloon-patch* function
- #(0 0 0 0
- -20356 3589 26184 18663 -32576 -24580 0 30 17367 16879 46 12348 15
- 24578 13016 20936 -4 8314 -44 20112 12319 21056 26120 19679 769
- 24602 24600 21312 12143 12 40 16192 44 19679 769 -8196 0 28 20085 12090
- -84 20085 425 6292 424 1202 -23552 558)))
-
- (defvar *last-item-menuid* nil)
- (defvar *last-item-num* nil)
-
- (defpascal lisp-hmShowMenuBalloon (:word item-num ; 2 = 2
- :word item-menuid ; + 2 = 4
- :long item-flags ; + 4 = 8
- :long item-reserved ; + 4 = 12
- :long tip ; + 4 = 16
- :ptr alternate-rect ; + 4 = 20
- :ptr tip-proc ; + 4 = 24
- :word the-proc ; + 2 = 26
- :word variant ; + 2 = 28
- :word) ; + 2 = 30 bytes on the stack
- (declare (ignore alternate-rect item-reserved item-flags
- tip-proc the-proc variant))
- (or (ignore-errors
- (and (or (not (#_hmIsBalloon))
- (not (and (eql item-num *last-item-num*)
- (eql item-menuid *last-item-menuid*))))
- (let ((menu (menu-object item-menuid)))
- (setq *last-item-num* item-num
- *last-item-menuid* item-menuid)
- (if menu
- (or (let* ((element (if (eql 0 item-num)
- (progn (#_hmRemoveBalloon)
- nil) ; don't display menu help while menu down
- (nth (1- item-num) (slot-value menu 'item-list))))
- (string (and element (checked-help-string element))))
- (if (and (null element) (eq menu *apple-menu*))
- #xffff ; pass through for system apple menu items
- (when string
- (show-balloon-string element string tip))))
- 0)
- #xffff)))) ; return of #xffff means let the help manager handle it.
- 0))
-
- (eval-when (compile load eval)
- (let ((*warn-if-redefine* nil))
- (defconstant _Pack14 #xa830))
- )
-
- (defvar *old-pack14-trap-address* nil)
- (defvar *pack14-patch-pointer* nil)
-
- (defun install-hmShowBalloon-patch ()
- (when *help-manager-present*
- (let ((p *pack14-patch-pointer*))
- (when p
- (#_SetTrapAddress :NewTool *old-pack14-trap-address* _Pack14)
- (setq *old-pack14-trap-address* nil
- *pack14-patch-pointer* nil)
- (#_DisposPtr p)))
- (let* ((patch-vector *hmShowMenuBalloon-patch*)
- (words (length patch-vector))
- (p (#_NewPtr (* 2 words)))
- (offset 0))
- (declare (fixnum offset words))
- (dotimes (i words)
- (declare (fixnum i))
- (setf (%get-word p offset) (uvref patch-vector i))
- (incf offset 2))
- (setq *old-pack14-trap-address* (#_GetTrapAddress :NewTool _Pack14)
- *pack14-patch-pointer* p)
- (setf (%get-ptr p 0) lisp-hmShowMenuBalloon
- (%get-ptr p 4) *old-pack14-trap-address*)
- (#_SetTrapAddress :NewTool (%inc-ptr p 8) _Pack14)
- p)))
-
- (defun start-hmShowBalloon-patch ()
- (setq *old-pack14-trap-address* nil
- *pack14-patch-pointer* nil)
- (install-hmshowballoon-patch))
-
- (pushnew 'start-hmshowballoon-patch *lisp-startup-functions*)
-
- (install-hmshowballoon-patch)
-
-
- (provide :help-manager)
-
-